#!/usr/bin/python
# Copyright (C) 
# 
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
##
# @file plain2bib.py
# @Synopsis: Convert from plain or Endnote reference file to the bib styple. 
# @author hkuieagle
# @version 0.1
# @date 2011-09-15
# @usage plain2bib filename.txt or plain2bib filename.do 

import sys,re,os
import copy

start_string="PT J\n"
end_string="ER\n"
# Feel free to add your new pairs below
convert_dict={"AU":"Author","TI":"Title","SO":"Journal","PY":"Year",
        "VL":"Volume","IS":"Number","PD":"Month","AB":"Abstract",
        "PU":"Publisher","PA":"Address","DT":"Type","LA":"Language",
        "RP":"Affiliation","DI":"DOI","AR":"Article-Number","SN":"ISSN",
        "DE":"Keywords","ID":"Keywords-Plus","SC":"Subject-Category",
        "EM":"Author-Email","FU":"Funding-Acknowledgement","FX":"Funding-Text",
        "NR":"Number-of-cited-References","TC":"Times-Cited","JI":"Journal-ISO",
        "GA":"Doc-Delivery-Number","UT":"Unique-ID", "BP":"Pages-", "EP":"Pages"}
# List contains plain_entry_dict s
plain_entries_list = []

# List contains bib_entry_dict s
bib_entries_list = []


# Create item list from entry_str which is a integrited string of the entry
def get_itemlist(entry_str):
    items_list = []
    for line in entry_str.splitlines():
        if not line[0:2].isspace():
            item_str = line
            for inter_line in entry_str.splitlines()[entry_str.splitlines().index(line)+1:]:
                if inter_line[0:2].isspace():
                    item_str += '\n' + inter_line
                else:
                    break
            items_list.append(item_str)
    return items_list

# Convert from bib_entry_dict to string type, as to write into files later
def dict2str(entry_dict):
    entry_str = ''
    for key in entry_dict.keys():
        entry_str += key + ' = ' + entry_dict[key]
    return entry_str

def special_char(char):
    return (not char.isdigit()) and (not char.isalpha())

if __name__ == '__main__':
    if len(sys.argv) != 2:
        print "Error in agument!"
        sys.exit(0)

    plain_items_list = []
    plain_file = open(sys.argv[1],'r')
    line = plain_file.readline()
    while len(line) != 0:
        if line == start_string:
            entry_str = ""
            line = plain_file.readline()
            while line != end_string:           # get the chunk of entry_str
                entry_str += line
                line = plain_file.readline()

            plain_items_list = get_itemlist(entry_str)      # convert the chunk to list of items
            plain_entry_dict = {}
            for item in plain_items_list:                   # create the dict from the list created above
                key = item[0:2]
                value = item[2:].lstrip()
                plain_entry_dict[key] = value

            plain_entries_list.append(plain_entry_dict)     # store the dicts in a container list
        line = plain_file.readline()
    plain_file.close()

    for entry_dict in plain_entries_list:
        bib_entry_dict = {}
        pairs_dict = {}
        for key in entry_dict.keys():
            if convert_dict.has_key(key):
                bib_key = convert_dict[key]
                if special_char(bib_key[-1]):
                    pairs_dict[bib_key[:-1]] = entry_dict[key] + bib_key[-1]
                    continue
                else:
                    if len(pairs_dict) == 0:
                        bib_value = '{' + entry_dict[key] + '},\n'
                    else:
                        if bib_key in pairs_dict:
                            bib_value = '{' + pairs_dict[bib_key] + entry_dict[key] + '},\n'
                            del pairs_dict[bib_key]
                        else:
                            bib_value = '{' + entry_dict[key] + '},\n'

                bib_entry_dict[bib_key] = bib_value         # create the bib_entry_dict from the plain dicts stored in the list above recursively
            else:
                print "Key:%s not found in the converting table, you can add it by yourself\n" %key
                continue
        if len(pairs_dict) != 0:
            cp_pairs_dict = copy.deepcopy(pairs_dict)
            for bib_key in cp_pairs_dict:
                if bib_key in bib_entry_dict:
                    bib_value = '{' + pairs_dict[bib_key] + bib_entry_dict[bib_key][1:-3] + '},\n'
                    bib_entry_dict[bib_key] = bib_value         # create the bib_entry_dict from the plain dicts stored in the list above recursively
                    del pairs_dict[bib_key]

        if len(pairs_dict) != 0:
            print "WARNING: remaining unmatched pairs!", pairs_dict, "\n"

        bib_entries_list.append(bib_entry_dict)             # store the bib dicts in another container list

    bib_file_name = os.path.splitext(sys.argv[1])[0] + '.bib'
    bib_file = open(bib_file_name, 'w')
    heading = "# %s generated by plain2bib.py from %s automaticly\n\n" %(os.path.basename(bib_file_name), os.path.basename(sys.argv[1]))
    bib_file.write(heading)
    for bib_entry_dict in bib_entries_list:
        bib_entry_str = dict2str(bib_entry_dict)
        essay_type = bib_entry_dict["Type"][1:-3] if bib_entry_dict.has_key("Type") else "article"
        bib_entry_str = "@"+ essay_type +'{' + bib_entry_dict["Unique-ID"][1:-3] + ',\n' + bib_entry_str + '}\n\n'
        bib_file.write(bib_entry_str)
    bib_file.close()
    print "Do converting successfully, see file: \"%s\"!\n" %(os.path.basename(bib_file_name))

